﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace FirmaKurierska.Models
{
    /// <summary>
    /// Klasa przeznaczona do realizacji algorytmów jednobazowych
    /// </summary>
    public class OperacjeJednobazowe
    {
        public void przelicz()
        {
            var baza = new PlacowkaEntities();
            var centralle = baza.Centrale.ToList();
            var listapaczek = baza.Paczka.ToList();
            var paczki_do_odebrania = new List<Paczka>();
            var paczki_do_dostarczenia = new List<Paczka>();
            var listasamochodow = baza.Samochod.ToList();
            List<Samochod>[] lista_dostepnych_samochodow = new List<Samochod>[20];
            for (int i = 0; i < 20; i++)
            {
                lista_dostepnych_samochodow[i] = new List<Samochod>();
            }
            var lista_niedostepnych_samochodow = new List<Samochod>();
            var do_zapisu = baza.Alg_jednobazowy.ToList();
            var ludzie = baza.Adresat.ToList();
            var trasa_dostarczenia = new List<Paczka>();
            var trasa_odebrania = new List<Paczka>();

            trasa_dostarczenia.Clear();
            trasa_odebrania.Clear();
            float[,] tab_sasiedztwa_dostarczanie = new float[1500, 1500];
            float[,] tab_sasiedztwa_odbieranie = new float[1500, 1500];
            int nr = 0, tst = 0;
            foreach (Paczka o in listapaczek)
            {
                if (o.status == 0)
                {
                    paczki_do_odebrania.Add(o);

                }
                else if (o.status == 6)
                {
                    paczki_do_dostarczenia.Add(o);
                }
            }
            foreach (Samochod o in listasamochodow)
            {
                if (o.w_bazie == true)
                {
                    lista_dostepnych_samochodow[(int)o.centrala_id].Add(o);
                }
                else
                {
                    lista_niedostepnych_samochodow.Add(o);
                }
            }
            int cent;
            foreach (Paczka o in paczki_do_odebrania)
            {
                cent = (int)o.centrala_id;
                nr++;
                if (lista_dostepnych_samochodow[cent].Count > 0)
                {
                    if (lista_dostepnych_samochodow[cent][0].obciazenie + o.waga < lista_dostepnych_samochodow[cent][0].ladownosc && o.centrala_id == lista_dostepnych_samochodow[cent][0].centrala_id)
                    {
                        o.status = 7;
                        o.kierowca_id = lista_dostepnych_samochodow[cent][0].kierowca_id;
                        lista_dostepnych_samochodow[cent][0].obciazenie = lista_dostepnych_samochodow[cent][0].obciazenie + o.waga;
                    }
                    else if (lista_dostepnych_samochodow[cent][0].obciazenie + o.waga > lista_dostepnych_samochodow[cent][0].ladownosc)
                    {
                        lista_niedostepnych_samochodow.Add(lista_dostepnych_samochodow[cent][0]);
                        lista_dostepnych_samochodow[cent].RemoveAt(0);
                    }
                    if (nr == paczki_do_odebrania.Count)
                    {
                        lista_niedostepnych_samochodow.Add(lista_dostepnych_samochodow[cent][0]);
                        lista_dostepnych_samochodow[cent].RemoveAt(0);
                    }
                }
            }
            nr = 0;
            foreach (Paczka o in paczki_do_dostarczenia)
            {
                cent = (int)o.centrala_id;
                nr++;
                if (lista_dostepnych_samochodow[cent].Count > 0)
                {
                    if (lista_dostepnych_samochodow[cent][0].obciazenie + o.waga < lista_dostepnych_samochodow[cent][0].ladownosc && o.centrala_id == lista_dostepnych_samochodow[cent][0].centrala_id)
                    {
                        o.status = 1;
                        o.kierowca_id = lista_dostepnych_samochodow[cent][0].kierowca_id;
                        lista_dostepnych_samochodow[cent][0].obciazenie = lista_dostepnych_samochodow[cent][0].obciazenie + o.waga;
                    }
                    else if (lista_dostepnych_samochodow[cent][0].obciazenie + o.waga > lista_dostepnych_samochodow[cent][0].ladownosc)
                    {
                        lista_niedostepnych_samochodow.Add(lista_dostepnych_samochodow[cent][0]);
                        lista_dostepnych_samochodow[cent].RemoveAt(0);
                    }
                    if (nr == paczki_do_dostarczenia.Count)
                    {
                        lista_niedostepnych_samochodow.Add(lista_dostepnych_samochodow[cent][0]);
                        lista_dostepnych_samochodow[cent].RemoveAt(0);
                    }
                }
            }
            int tmp = 0, tmp1 = 0, rozm = paczki_do_dostarczenia.Count + 1, tmp_id;
            int tmp_kierID = -10;
            var lista_do_usuniecia = new List<Paczka>();
            while (paczki_do_dostarczenia.Count > 0)
            {
                int centrala = (int)paczki_do_dostarczenia[0].centrala_id;
                licz_tablice(paczki_do_dostarczenia, tab_sasiedztwa_dostarczanie, centrala, centralle);
                trasa_dostarczenia.Clear();
                lista_do_usuniecia.Clear();
                tmp_kierID = -10;
                for (int j = 1; j < paczki_do_dostarczenia.Count + 1; j++)
                {
                    if (paczki_do_odebrania[j - 1].centrala_id != centrala) break;
                    for (int i = 1; i < paczki_do_dostarczenia.Count + 1; i++)
                    {
                        if (paczki_do_dostarczenia[i - 1].centrala_id != centrala) break;
                        if (tab_sasiedztwa_dostarczanie[tmp1, i] < tab_sasiedztwa_dostarczanie[tmp1, i - 1] && tab_sasiedztwa_dostarczanie[tmp1, i] > 0 || tab_sasiedztwa_dostarczanie[tmp1, i - 1] == 0)
                        {
                            if (tmp_kierID < -1 && paczki_do_dostarczenia[i - 1].kierowca_id.HasValue)
                            {
                                tmp_kierID = (int)paczki_do_dostarczenia[i - 1].kierowca_id;
                                tmp = i;
                            }
                            else if (tmp_kierID > -1) tmp = i;
                            if (paczki_do_dostarczenia[i - 1].kierowca_id.HasValue == false)
                            {
                                lista_do_usuniecia.Add(paczki_do_dostarczenia[i - 1]);
                            }
                        }

                    }
                    for (int i = 0; i < rozm; i++)
                    {
                        tab_sasiedztwa_dostarczanie[i, tmp1] = 0;
                        tab_sasiedztwa_dostarczanie[tmp1, i] = 0;
                    }

                    if (tmp > 0)
                    {
                        if (paczki_do_dostarczenia[tmp - 1].kierowca_id == tmp_kierID)
                        {
                            trasa_dostarczenia.Add(paczki_do_dostarczenia[tmp - 1]);
                            lista_do_usuniecia.Add(paczki_do_dostarczenia[tmp - 1]);
                        }
                    }
                    tmp1 = tmp;
                    tmp = 0;
                }


                foreach (Paczka o in trasa_dostarczenia)
                {
                    if (do_zapisu.Count == 0) tmp_id = 1;
                    else tmp_id = do_zapisu.Last().Jednobazowy_id + 1;
                    Alg_jednobazowy tmp_alg = new Alg_jednobazowy();
                    tmp_alg.data = o.data_nadania;
                    tmp_alg.Jednobazowy_id = tmp_id;
                    tmp_alg.Paczka = o;
                    tmp_alg.PaczkaID = o.pid;
                    foreach (Samochod p in listasamochodow)
                    {
                        if (o.kierowca_id == p.kierowca_id && p.w_bazie == true && o.centrala_id == p.centrala_id)
                        {
                            tmp_alg.Samochod = p;
                            tmp_alg.SamochodID = p.sid;
                            tst++;
                            break;
                        }
                    }
                    if (tst == 0) o.status = 6;
                    tmp_alg.Zrealizowane = false;
                    if (o.status != 6) do_zapisu.Add(tmp_alg);
                }
                foreach (Paczka o in lista_do_usuniecia)
                {
                    paczki_do_dostarczenia.Remove(o);
                }
            }
            tmp = 0;
            tst = 0;
            tmp1 = 0;
            rozm = paczki_do_odebrania.Count + 1;
            tmp_kierID = -10;
            while (paczki_do_odebrania.Count > 0)
            {
                int centrala = (int)paczki_do_odebrania[0].centrala_id;
                licz_tablice(paczki_do_odebrania, tab_sasiedztwa_odbieranie, centrala, centralle);
                trasa_odebrania.Clear();
                lista_do_usuniecia.Clear();
                tmp_kierID = -10;
                for (int j = 1; j < paczki_do_odebrania.Count + 1; j++)
                {
                    if (paczki_do_odebrania[j - 1].centrala_id != centrala) break;

                    for (int i = 1; i < paczki_do_odebrania.Count + 1; i++)
                    {
                        if (paczki_do_odebrania[i - 1].centrala_id != centrala) break;
                        if (tab_sasiedztwa_odbieranie[tmp1, i] < tab_sasiedztwa_odbieranie[tmp1, i - 1] && tab_sasiedztwa_odbieranie[tmp1, i] > 0 || tab_sasiedztwa_odbieranie[tmp1, i - 1] == 0)
                        {
                            if (tmp_kierID < -1 && paczki_do_odebrania[i - 1].kierowca_id.HasValue)
                            {
                                tmp_kierID = (int)paczki_do_odebrania[i - 1].kierowca_id;
                                tmp = i;
                            }
                            else if (tmp_kierID > -1) tmp = i;
                            if (paczki_do_odebrania[i - 1].kierowca_id.HasValue == false)
                            {
                                lista_do_usuniecia.Add(paczki_do_odebrania[i - 1]);
                            }
                        }

                    }
                    for (int i = 0; i < rozm; i++)
                    {
                        tab_sasiedztwa_odbieranie[i, tmp1] = 0;
                        tab_sasiedztwa_odbieranie[tmp1, i] = 0;
                    }
                    if (tmp > 0 && paczki_do_odebrania[tmp - 1].kierowca_id == tmp_kierID)
                    {
                        trasa_odebrania.Add(paczki_do_odebrania[tmp - 1]);
                        lista_do_usuniecia.Add(paczki_do_odebrania[tmp - 1]);
                    }
                    tmp1 = tmp;
                    tmp = 0;

                }

                foreach (Paczka o in trasa_odebrania)
                {

                    if (do_zapisu.Count == 0) tmp_id = 1;
                    else tmp_id = do_zapisu.Last().Jednobazowy_id + 1;
                    Alg_jednobazowy tmp_alg = new Alg_jednobazowy();
                    tmp_alg.data = o.data_nadania;
                    tmp_alg.Jednobazowy_id = tmp_id;
                    tmp_alg.Paczka = o;
                    tmp_alg.PaczkaID = o.pid;
                    foreach (Samochod p in listasamochodow)
                    {
                        if (o.kierowca_id == p.kierowca_id && p.w_bazie == true && o.centrala_id == p.centrala_id)
                        {
                            tmp_alg.Samochod = p;
                            tmp_alg.SamochodID = p.sid;
                            tst++;
                            break;
                        }
                    }
                    if (tst == 0) o.status = 0;
                    tmp_alg.Zrealizowane = false;
                    if (o.status != 0) do_zapisu.Add(tmp_alg);
                }
                foreach (Paczka o in lista_do_usuniecia)
                {
                    paczki_do_odebrania.Remove(o);
                }
            }
            baza.SaveChanges();

        }
        void licz_tablice(List<Paczka> paczki, float[,] tab_sasiedztwa, int centrala, List<Centrale> centrale)
        {
            Lokalizacja lok = new Lokalizacja();
            paczki = paczki.OrderBy(o => o.centrala_id).ToList();

            for (int i = 0; i < paczki.Count + 1; i++)
            {
                tab_sasiedztwa[i, i] = 0;
                for (int j = i + 1; j < paczki.Count + 1; j++)
                {
                    if (paczki[j - 1].centrala_id == centrala)
                    {
                        if (i == 0)
                        {
                            tab_sasiedztwa[i, j] = lok.wyliczOdleglosc(centrale[centrala].ulica, Int32.Parse(centrale[centrala].nrDomu), centrale[centrala].Miejscowosc, paczki[j - 1].Adresat.ulica, paczki[j - 1].Adresat.nr_domu, paczki[j - 1].Adresat.miasto);
                            tab_sasiedztwa[j, i] = tab_sasiedztwa[i, j];
                        }
                        else
                        {
                            tab_sasiedztwa[i, j] = lok.wyliczOdleglosc(paczki[i - 1].Adresat.ulica, paczki[i - 1].Adresat.nr_domu, paczki[i - 1].Adresat.miasto, paczki[j - 1].Adresat.ulica, paczki[j - 1].Adresat.nr_domu, paczki[j - 1].Adresat.miasto);
                            tab_sasiedztwa[j, i] = tab_sasiedztwa[i, j];
                        }
                    }
                }
            }
        }
    }
}